package zaplog

import (
	"fmt"
	"io"
	"time"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

/**
 * 日志配置
 */
type LogConfig struct {
	Path   string                 `yaml:"path"`
	Level  string                 `yaml:"level"`
	Fields map[string]interface{} `yaml:"fields"`
	MaxAge int                    `yaml:"max_age"`
}

func NewZapLog(cfg LogConfig) *zap.Logger {
	var (
		l   zapcore.Level = zap.DebugLevel
		err error
	)

	encoderConfig := zapcore.EncoderConfig{
		TimeKey:       "time",
		LevelKey:      "level",
		NameKey:       "logger",
		CallerKey:     "caller",
		MessageKey:    "msg",
		StacktraceKey: "stacktrace",
		LineEnding:    zapcore.DefaultLineEnding,
		EncodeLevel:   zapcore.LowercaseLevelEncoder, // 小写编码器
		EncodeTime:    zapcore.ISO8601TimeEncoder,    // ISO8601 UTC 时间格式
		EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendInt64(int64(d) / 1000000)
		},
		EncodeCaller: zapcore.FullCallerEncoder, // 全路径编码器
	}

	err = l.Set(cfg.Level)
	if err != nil {
		panic(fmt.Sprintf("log init fail: %v", err))
	}

	logWriter := getWriter(cfg.Path, cfg.MaxAge)
	core := zapcore.NewTee(
		zapcore.NewCore(zapcore.NewJSONEncoder(encoderConfig), zapcore.AddSync(logWriter), l),
	)

	var options []zap.Option
	// 开启开发模式，堆栈跟踪
	options = append(options, zap.AddCaller())
	options = append(options, zap.AddCallerSkip(1))

	// error 级别打印堆栈
	options = append(options, zap.AddStacktrace(zap.ErrorLevel))

	// 开启文件及行号
	options = append(options, zap.Development())

	// 设置初始化字段
	fields := []zapcore.Field{}
	for k, v := range cfg.Fields {
		tmpField := zap.String(k, v.(string))

		fields = append(fields, tmpField)
	}

	options = append(options, zap.Fields(fields...))

	// 构造日志
	logger := zap.New(core, options...)

	return logger
}

func getWriter(filename string, archiveTime int) io.Writer {
	if archiveTime < 5 { //日志存档时间小于5天时，默认更新为30天
		archiveTime = 30
	}
	var withMaxAge = time.Duration(archiveTime) * 24 * time.Hour
	hook, err := rotatelogs.New(
		filename+".%Y-%m-%d", //info.log.2021-10-22
		//rotatelogs.WithLinkName(filename),         //为最新的日志建立软连接
		rotatelogs.WithMaxAge(withMaxAge),         //默认保存30天
		rotatelogs.WithRotationTime(time.Hour*24), //切割频率 24小时
	)
	if err != nil {
		panic(err)
	}
	return hook
}
